package com.iespring.aspect;

import com.iespring.anno.OperationLog;
import com.iespring.bean.admin.user.bo.MarketOrderShipBo;
import com.iespring.bean.admin.user.entity.*;
import com.iespring.bean.common.BaseRespVo;
import com.iespring.mapper.admin.MallLogMapper;
import com.iespring.mapper.admin.MallOrderMapper;
import com.iespring.mapper.admin.SysMapper;
import com.iespring.util.map.ActionTypeUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;

/**
 * 系统管理模块：操作日志
 * @author xD
 * @since 2022/12/28 19:48
 */
@Component
@Aspect
public class OperationLogAspect {

    @Resource
    MallLogMapper logMapper;

    @Resource
    MallOrderMapper orderMapper;

    @Resource
    SysMapper sysMapper;

    @Pointcut("@annotation(com.iespring.anno.OperationLog)")
    public void logPointcut() {
    }

    @Transactional
    @Around("logPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MallLog log = new MallLog();
        log.setAddTime(new Date());
        log.setUpdateTime(new Date());

        // 通过反射获取注解中的type和action
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        OperationLog annotation = method.getAnnotation(OperationLog.class);
        int type = annotation.type();
        String action = annotation.action();
        log.setType(type);
        log.setAction(action);

        // 通过request获取ip
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = sra.getRequest();
        String ip = request.getRemoteHost();
        log.setIp(ip);

        // 获取管理员信息logout
        MallAdmin marketAdmin = null;
        Subject subject = SecurityUtils.getSubject();
        PrincipalCollection principals = subject.getPrincipals();
        if (principals != null) {
            marketAdmin = (MallAdmin) principals.getPrimaryPrincipal();
            String username = marketAdmin.getUsername();
            log.setAdmin(username);
        }

        BaseRespVo proceed = null;
        try {
            proceed = (BaseRespVo) joinPoint.proceed();
        } catch (UnknownAccountException | IncorrectCredentialsException e) {
            log.setAdmin("匿名用户");
            proceed = BaseRespVo.invalidParameter("用户名或账号密码不正确");
        }
        String errmsg = proceed.getErrmsg();
        int errno = proceed.getErrno();
        Object data = proceed.getData();

        // 获取管理员信息login
        if (principals == null) {
            principals = subject.getPrincipals();
            if (principals != null) {
                marketAdmin = (MallAdmin) principals.getPrimaryPrincipal();
                String username = marketAdmin.getUsername();
                log.setAdmin(username);
            } else {
                log.setAdmin("匿名用户");
            }
        }

        // 操作状态：失败
        if (errno != 0) {
            log.setStatus(false);
            log.setResult(errmsg);
            logMapper.insertSelective(log);
            return proceed;
        }

        // 操作状态：成功
        // 获取操作结果
        Object[] args = joinPoint.getArgs();
        if ("添加管理员".equals(action)) {
            // 操作结果：添加管理员名称
            MarketAdminCreateVo createVo = (MarketAdminCreateVo) data;
            log.setResult(createVo.getUsername());
        } else if ("编辑管理员".equals(action)) {
            // 操作结果：编辑管理员新的名称
            MarketAdminUpdateVo updateVo = (MarketAdminUpdateVo) data;
            log.setResult(updateVo.getUsername());
        } else if ("删除管理员".equals(action)) {
            // 操作结果：删除管理员名称
            MallAdmin deleteAdmin = (MallAdmin) args[0];
            log.setResult(deleteAdmin.getUsername());
        } else if ("订单发货".equals(action)) {
            // 操作结果：订单编号
            MarketOrderShipBo shipBo = (MarketOrderShipBo) args[0];
            Integer orderId = shipBo.getOrderId();
            MallOrder mallOrder = orderMapper.selectByPrimaryKey(orderId);
            log.setResult("订单编号：" + mallOrder.getOrderSn());
        } else if ("删除订单".equals(action)) {
            // 操作结果：订单编号
            Map map = (Map) args[0];
            Integer orderId = (Integer) map.get("orderId");
            MallOrder mallOrder = orderMapper.selectByPrimaryKey(orderId);
            log.setResult("订单编号：" + mallOrder.getOrderSn());
        }

        log.setStatus(true);
        logMapper.insertSelective(log);

        return proceed;
    }
    /**
     * 记录所有admin的操作，登录除外，登录由logPointcut 实现
     * @return void
     * @author 杨宇健
     * @since 2022/12/30 15:00
     */
    @Pointcut("execution(* com..controller.admin..*(..))")
    public void logAllPointcut(){}
    @Around("logAllPointcut()")
    public Object logAllArround(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        MallLog log = new MallLog();

        HttpServletRequest request = sra.getRequest();
        String uri = request.getRequestURI();
        Integer type = ActionTypeUtils.getType(uri);
        String label = ActionTypeUtils.getLabel(type);
        String permission = ActionTypeUtils.getPermission(uri);
        String ip = request.getRemoteHost();
        //log.setIp(ip);
        //从数据库获取操作action
        String action = "";
        try {
            action = sysMapper.selectDetailLabel(permission);
        }catch (Exception e){
            action = permission;
        }

        if (action == null) {
            action = permission;
        }
        BaseRespVo proceed = null;
        //if (type == 1 || type == 2) {
        //    return null;
        //}
        try {
            //不按BaseRespVo的不拦截
            //TODO 拦截非BaseRespVo
            Object proceedPre = joinPoint.proceed();
            if (proceedPre == null) {
                return proceedPre;
            }
            if (!proceedPre.getClass().getSimpleName().equals("BaseRespVo")) {
                return proceedPre;
            }

            proceed = (BaseRespVo) proceedPre;
        } catch (UnknownAccountException | IncorrectCredentialsException e) {
            log.setAdmin("匿名用户");
            proceed = BaseRespVo.invalidParameter("用户名或账号密码不正确");
        }
        String errmsg = proceed.getErrmsg();
        int errno = proceed.getErrno();
        Object data = proceed.getData();


        //不处理的条件，type == 1（登录） 2（order）交给上面的代码处理，查询不记录，空包不记录
        if (type == 1 || type == 2 || permission.contains("admin:profile") || action.contains("查询")) {
            return proceed;
        }
        log.setStatus(true);

        log.setType(type);
        log.setAddTime(new Date());
        log.setUpdateTime(new Date());
        log.setAction(action);
        log.setResult("成功");
        log.setIp(ip);
        log.setDeleted(false);
        if (errno != 0) {
            log.setStatus(false);
            log.setResult(errmsg);
            logMapper.insertSelective(log);
            return proceed;
        }
        // 获取管理员信息
        MallAdmin marketAdmin = null;
        //TODO 没有获取到管理员
        Subject subject = SecurityUtils.getSubject();
        PrincipalCollection principals = subject.getPrincipals();
        if (principals != null) {
            marketAdmin = (MallAdmin) principals.getPrimaryPrincipal();
            String username = marketAdmin.getUsername();
            log.setAdmin(username);
        }
        logMapper.insert(log);
        return proceed;
    }
}
